﻿namespace Reals.Parellel
{
  #region Using directives

  using System;
  using System.Collections.Generic;
  using System.Text;

  using Reals.Utils.Threading;
  #endregion

  /// <summary>
  /// 微过程时序分支.
  /// </summary>
  /// <remarks>
  /// 因为涉及到时序的同步,
  /// 设计上不支持从外部(接口)
  /// 直接生成分支.
  /// 但是在静态构造中
  /// 可以添加子层以实现
  /// 树状结构.
  /// </remarks>
  public interface MicroBranch : MicroThread
  {
    /// <summary>
    /// 获取或设定分支状态.
    /// </summary>
    /// <remarks>
    /// 改变分支状态是一个异步操作.
    /// 它需要在最后一个等时面处理
    /// 之后以及第一个等时面处理
    /// 之前发生.这可以保证第一个
    /// 等时面都是同步的.
    /// 可以通过设定或者撤销来
    /// 决定是否分支.但是一旦分支
    /// 完成分支状态将自动置为
    /// false.
    /// </remarks>
    bool Branching { get;set;}
    /// <summary>
    /// 获取当前分支是否具有子层.
    /// </summary>
    bool HasChildren { get;}
    /// <summary>
    /// 用于线程同步的障碍.
    /// </summary>
    SyncBarrier Barrier { get;}
    /// <summary>
    /// 分支树的根.
    /// </summary>
    MicroBranch Root { get;}
    /// <summary>
    /// 父层分支.
    /// </summary>
    MicroBranch Parent { get;}
    /// <summary>
    /// 子层分支(按分支发生的时间顺序排列).
    /// </summary>
    MicroTimingBranchList Children { get;}
  }

  /// <summary>
  /// 微过程时序分岔器的实现.
  /// </summary>
  public class MicroBranchImpl : MicroThreadImpl, MicroBranch
  {
    #region Shortcuts
    public new static MicroBranch it()
    {
      return new MicroBranchImpl();
    }
    public static MicroBranch of(MicroBranch parent)
    {
      return new MicroBranchImpl(parent);
    }
    public static MicroBranch of(MicroBranch parent, SyncBarrier barrier, params MicroBranch[] children)
    {
      return new MicroBranchImpl(parent, barrier, children);
    }
    #endregion
    #region Fields
    protected bool branching = false;
    protected SyncBarrier barrier = null;
    protected MicroBranch parent = null;
    protected MicroTimingBranchList children = null;
    #endregion
    #region Properties
    public virtual bool Branching { get { return this.branching; } set { this.branching = value; } }
    public virtual bool HasChildren { get { return this.children != null && this.children.Count != 0; } }
    public virtual MicroBranch Parent { get { return this.parent; } }
    public virtual MicroBranch Root { get { return (this.parent == this || this.parent == null) ? this : this.parent.Parent; } }
    public virtual MicroTimingBranchList Children { get { return this.GetChildren(); } }
    public virtual SyncBarrier Barrier { get { return this.barrier; } }
    protected virtual bool IsCurrentLayerFirst
    {
      get { return this.currentSyncLayer == 0; }
    }
    protected virtual bool IsCurrentLayerLast
    {
      get { return this.currentSyncLayer == this.MicroSynchings.Count - 1; }
    }

    #endregion
    #region Constructors
    public MicroBranchImpl() : base() { this.parent = this; this.barrier = new SyncBarrierImpl(); }
    public MicroBranchImpl(MicroBranch parent) : this(parent, parent.Barrier) { }
    public MicroBranchImpl(MicroBranch parent, params MicroBranch[] children) : this(parent, parent.Barrier, children) { }
    public MicroBranchImpl(MicroBranch parent, SyncBarrier barrier) : this(parent, barrier, null) { }
    public MicroBranchImpl(MicroBranch parent, SyncBarrier barrier, params MicroBranch[] children)
    {
      if (parent == null)
      {
        throw new ArgumentNullException("parent", "Parent can not be null!");
      }
      this.parent = parent;

      this.barrier = (barrier == null) ? parent.Barrier : barrier;

      if (this.barrier == null)
      {
        throw new ArgumentNullException("barrier", "Barrier is null or parent.Barrier is null!");
      }
      //Append this into barrier threads.
      this.barrier.TotalThreads++;

      if (children != null)
      {
        foreach (MicroBranch child in children)
        {
          if (child != null)
          {
            this.Children.Add(child);
          }
        }
      }
    }
    #endregion
    #region Methods
    /// <summary>
    /// 重写此方法以实现所有子层的启动.
    /// </summary>
    public override void Start()
    {
      base.Start();
      if (this.HasChildren)
      {
        this.Children.StartBranches();
      }
    }

    /// <summary>
    /// 重写此方法以实现所有子层的终止.
    /// </summary>
    public override void Terminate()
    {
      if (this.HasChildren)
      {
        this.Children.TerminateBranches();
      }
      base.Terminate();
    }

    /// <summary>
    /// 次方法应由运行中的线程调用,以确保在指定的等时面上
    /// 正确的分支得到启动.
    /// </summary>
    protected virtual MicroBranch Fork()
    {
      MicroBranch branch = this.CreateBranch(this);
      this.children.Add(branch);
      return branch;
    }

    protected virtual MicroBranch CreateBranch(MicroBranch parent)
    {
      return new MicroBranchImpl(this);
    }
    protected virtual MicroTimingBranchList GetChildren()
    {
      return (this.children != null) ? this.children : this.children = new MicroTimingBranchListImpl();
    }

    protected override void OnSynchCurrentLayer(MicroSynching layer)
    {
      //可以分支的条件.
      if (this.Branching && this.IsCurrentLayerLast)
      {
        //在屏障中添加一个线程.
        this.Barrier.ExchangingThreads = 1;
      }
      this.Barrier.Stride();

      base.OnSynchCurrentLayer(layer);

      if (this.Branching && this.IsCurrentLayerLast)
      {
        //进行分支,并启动分支.
        this.Fork().Start();
        //分支已经实现,将Branching置为false.
        this.Branching = false;
      }
    }
    #endregion
  }

  /// <summary>
  /// 微过程时序分支列表.
  /// </summary>
  public interface MicroTimingBranchList : ICollection<MicroBranch>
  {
    /// <summary>
    /// 启动所有分支
    /// </summary>
    void StartBranches();
    /// <summary>
    /// 终止所有分支
    /// </summary>
    void TerminateBranches();
  }

  /// <summary>
  /// 微过程时序分支列表实现.
  /// </summary>
  public class MicroTimingBranchListImpl : LinkedList<MicroBranch>, MicroTimingBranchList
  {
    #region Constructors
    public MicroTimingBranchListImpl() { }
    #endregion
    #region Methods
    public virtual void StartBranches()
    {
      LinkedListNode<MicroBranch> node = this.First;

      while (node != null)
      {
        node.Value.Start();
        node = node.Next;
      }

    }
    public virtual void TerminateBranches()
    {
      LinkedListNode<MicroBranch> node = this.Last;

      while (node != null)
      {
        node.Value.Start();
        node = node.Previous;
      }
    }
    #endregion
  }


}
